import { views_factory } from "@/Factory";
import { GlobalValue } from "@/GlobalValue";
import { Paths } from "@/paths";
import { IEditorInfo } from "@/views/EditorView/IEditorInfo";
import { Slot } from "@/views/WorkspacesView";
import QueryString from "qs";
import { useCallback, useMemo } from "react";
import { useRefNow } from "../useRefNow";

const __debugging = false;
const editor_groups: Paths.All[][] = [
  [
    Paths.All.LocalWXContacts,
    Paths.All.LocalWXSessions,
    Paths.All.RemoteChat
  ],
  [
    Paths.All.WXContactsManagement,
    Paths.All.WXSessionsManagement,
    Paths.All.WXAccountManagement,
    Paths.All.WXMessagesManagement,
  ],
  [Paths.All.LocalChat], // “消息列表”,
  [Paths.All.DevTasks, Paths.All.About], // “关于”
]

export interface IOpenEditor {
  (...infos: (IEditorInfo | string)[]): void;
}

/** 
 * @todo 被react的hook逻辑绕进去了，导致函数连续调用时，表现与预期不一样，需要修复。 -Gim
 */
export function useOpenEditor(): IOpenEditor {
  const [{ workspaces, actived_slot, slot_infos }, , dispatch] = GlobalValue.use()
  __debugging && useMemo(() => console.log(JSON.parse(JSON.stringify(slot_infos)), slot_infos), [slot_infos])
  const names = Paths.useNames();
  const func: IOpenEditor = (...infos: (IEditorInfo | string)[]) => {
    if (!workspaces) {
      console.warn(`[${useOpenEditor.TAG}] workspaces got ${workspaces}`)
      return;
    }
    const slot_info_list = [
      ...Object.keys(slot_infos).map(key => slot_infos[key]!).filter(Boolean)
    ]
    for (let info of infos) {

      if (typeof info === 'string') {
        const [path, search] = info.split('?')
        const data = search ? QueryString.parse(search) : void 0
        info = {
          uid: info,
          kind: path,
          title: data?.title ? ('' + data?.title) : '',
          data: data,
        }
      }

      const fallback_title: string | undefined = (names as any)[info.kind]
      info.title = info.title || fallback_title || info.kind;


      // 优先打开已存在的editor
      let is_open_exists = false
      for (const k in slot_infos) {
        const slot_info = slot_infos[k]!;
        const editor_info = slot_info.editors.find(v => v.uid === info.uid);
        if (!editor_info) continue;
        slot_info_list.push({ ...slot_info, actived: editor_info })
        is_open_exists = true;
        break;
      }
      if (is_open_exists) continue;
      // dispatch([GlobalValue.Type.SetSlotInfo, new_slot_info]);
      // dispatch([GlobalValue.Type.SetActivedSlot, workspaces.slots.get(new_slot_info.id) as any]);

      let is_group_match: boolean = false;
      /** 同组editor的尽量放在相同的slot  */
      for (const members of editor_groups) {
        is_group_match = members.some(v => info.kind === v)
        if (!is_group_match) continue;
        const target_slots: [number, GlobalValue.IEditorsSlotInfo][] = [];

        for (const slot of slot_info_list) {
          let score = 0;
          const actived_editor_match = members.some(v => slot.actived?.kind === v);
          const has_editor_match = slot.editors.some(other => members.some(v => other.kind === v));
          if (actived_editor_match) score++;
          if (has_editor_match) score++
          if (has_editor_match && actived_slot?.id === slot.id) score++;
          if (score > 0) target_slots.push([score, slot] as any);
        }

        // 将editor放入得分最高的slot
        __debugging && console.debug(`[${useOpenEditor.TAG}] 查找潜在slots`, JSON.parse(JSON.stringify(slot_infos)))
        const slot_info = target_slots.sort((a, b) => b[0] - a[0])?.[0]?.[1];
        if (!slot_info) break;

        const index = slot_info.editors.findIndex(v => v.uid === slot_info.actived?.uid)
        const editors = [...slot_info.editors];
        editors.splice(index + 1, 0, info);

        const idx = slot_info_list.indexOf(slot_info)
        slot_info_list[idx] = {
          ...slot_info,
          editors,
          actived: info,
        }
        is_open_exists = true
        break;
      }
      if (is_open_exists) continue;
      // dispatch([GlobalValue.Type.SetSlotInfo, new_slot_info]);

      /** 有分组，却没找到匹配的slot，就另外再开一个slot */
      if (is_group_match) {
        __debugging && console.debug(`[${useOpenEditor.TAG}] 找到匹配组，但无slot可用，將創建新slot`)
        const slot_id = 'EDITORS#' + views_factory.new_uid
        const slot = new Slot(workspaces, { id: slot_id })
        const idx = editor_groups.findIndex(a => a.some(b => info.kind === b))
        workspaces.root.insert(idx, slot)
        workspaces.confirm();
        const weight = workspaces.root.weight;
        if (workspaces.root.children.length == 2 && weight > 700) {
          workspaces.root.children[0].weight = 350;
          workspaces.root.children[1].weight = weight - 350;
          workspaces.root.confirm();
        }
        slot_info_list.push({
          id: slot_id,
          editors: [info],
          actived: info
        })
        continue;
      }

      __debugging && console.debug(`[${useOpenEditor.TAG}] 未找到匹配组`)

      // 优先在已激活的slot打开editor
      if (actived_slot) {
        const idx = slot_info_list.findIndex(info => info.id === actived_slot.id)
        if (idx >= 0) {
          const slot_info = slot_info_list[idx]
          slot_info_list[idx] = {
            ...slot_info,
            editors: [...slot_info.editors, info],
            actived: info
          }
        }
      }

      const slot_id = 'EDITORS#' + views_factory.new_uid
      const slot = new Slot(workspaces, { id: slot_id })
      switch (info.kind as Paths.All) {
        case Paths.All.LocalWXContacts:
        case Paths.All.LocalWXSessions:
          workspaces.root.insert(0, slot);
          workspaces.confirm();
          break;
        default:
          workspaces.root.push(slot);
          workspaces.confirm();
          break;
      }
      slot_info_list.push({
        id: slot_id,
        editors: [info],
        actived: info
      })
    }
    dispatch([GlobalValue.Type.SetSlotInfos, slot_info_list])
  }
  const ref_func = useRefNow(func);
  return useCallback<IOpenEditor>((...info) => ref_func.current(...info), [])
}
useOpenEditor.TAG = 'useOpenEditor'